﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using Pavilion.DesignerTool;
using Pavilion.DesignerTool.ViewTools.ConnectableListBox;

namespace Pavilion.DesignerTool.ViewTools
{

    public static class Dragger
    {
        private static FrameworkElement currentlyDraggedElement;
        private static FrameworkElement CurrentlyDraggedElement
        {
            get { return currentlyDraggedElement; } 
            set
            {
                if (CurrentlyDraggedElement != null)
                {
                    CurrentlyDraggedElement.MouseMove -= new MouseEventHandler(CurrentlyDraggedElement_MouseMove);
                    CurrentlyDraggedElement.MouseLeftButtonUp -= new MouseButtonEventHandler(CurrentlyDraggedElement_MouseLeftButtonUp);
                }

                currentlyDraggedElement = value;

                if (CurrentlyDraggedElement != null)
                {
                    CurrentlyDraggedElement.MouseMove += new MouseEventHandler(CurrentlyDraggedElement_MouseMove);
                    CurrentlyDraggedElement.MouseLeftButtonUp +=new MouseButtonEventHandler(CurrentlyDraggedElement_MouseLeftButtonUp);
                }
            }           
        }

        private static ItemPreviewAdorner adornerForDraggedItem;
        private static ItemPreviewAdorner AdornerForDraggedItem
        {
            get { return adornerForDraggedItem; }
            set { adornerForDraggedItem = value; }
        }

        #region IsDraggable

        public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.RegisterAttached("IsDraggable", typeof(Boolean), typeof(Dragger),
            new FrameworkPropertyMetadata(IsDraggable_PropertyChanged));

        public static void SetIsDraggable(DependencyObject element, Boolean value)
        {
            element.SetValue(IsDraggableProperty, value);
        }
        public static Boolean GetIsDraggable(DependencyObject element)
        {
            return (Boolean)element.GetValue(IsDraggableProperty);
        }
 
        #endregion

        #region ItemDraggedEvent

        public static readonly RoutedEvent ItemDraggedEvent = EventManager.RegisterRoutedEvent("ItemDragged", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(Dragger));

        public static event RoutedEventHandler ItemDragged;

        public static void AddItemDraggedHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.AddHandler(Dragger.ItemDraggedEvent, handler);
            }
        }

        public static void RemoveItemDraggedEventHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.RemoveHandler(Dragger.ItemDraggedEvent, handler);
            }
        }
       
        #endregion

        public static void IsDraggable_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if ((bool)args.NewValue == true)
            {
                FrameworkElement element = (FrameworkElement)obj;
                element.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(ItemToBeDragged_MouseLeftButtonDown);
            }
        }

        private static void ItemToBeDragged_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            var element = sender as FrameworkElement;
            if (element != null)
            {
                CurrentlyDraggedElement = element;
            }
        }

        private static void CurrentlyDraggedElement_MouseMove(object sender, MouseEventArgs e)
        {
            var element = sender as FrameworkElement;

            if (element.IsEnabled == true)
            {
                element.CaptureMouse();
                DragElement(element);
            }         
        }

        private static void CurrentlyDraggedElement_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;

            if (element.DataContext as IConnectableItem != null)
                (element.DataContext as IConnectableItem).Position = ObtainCurrentPosition(element);

            CurrentlyDraggedElement = null;
            element.ReleaseMouseCapture();
        }

        private static Point DragElement(FrameworkElement element)
        {
            Point position = ObtainCurrentPosition(element);

            element.RenderTransform = ReturnTransFormGroup(position.X, position.Y);
            element.RaiseEvent(new ItemDraggedRoutedEventArgs(element, position, ItemDraggedEvent));

            return position;
        }

        private static Point ObtainCurrentPosition(FrameworkElement element)
        {
            var canvas = PavilionVisualTreeHelper.GetAncestor(element, typeof(Canvas)) as IInputElement;

            return new Point(Mouse.GetPosition(canvas).X - element.ActualWidth / 2, Mouse.GetPosition(canvas).Y - element.ActualHeight / 2);
        }

        private static TransformGroup ReturnTransFormGroup(double mouseX, double mouseY)
        {
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(new TranslateTransform(mouseX, mouseY));
            return transformGroup;
        }
    }
    
    public class ItemDraggedRoutedEventArgs : RoutedEventArgs
    {
        public Point LocationDraggedTo { get; set;}
        public FrameworkElement ElementBeingDragged { get; set; }
        
        public ItemDraggedRoutedEventArgs(DependencyObject elementBeingDragged, Point locationDraggedTo, RoutedEvent routedEvent)
            : base(routedEvent)
        {
            this.ElementBeingDragged = elementBeingDragged as FrameworkElement;
            LocationDraggedTo = locationDraggedTo;            
        }
    }
}



/*
 * On MouseMove, if left Mouse Button is down & adorner has not been created we create Adorner 
 * 
 * If adorner has been created mouse capture the adorner
 * 
 * Move Adorner to location of mouse
 * 
 * On Mouse Up, we translate the element to the position of the adorner.
 * 
 * release the mouse capture
 * 
 */
